/* Original Author:  Dominick O'Dierno
 * Date: 2007   odiernod@gmail.com     --Originally intended for use with DOMercury:  http://www.odierno.com/domercury
 * Description: Handles the loading and access of plugins.
 * 
 * NOTE: Some of this code was not originally mine, but I have heavily modified it to meet the needs of DOMercury.  If 
 * anyone knows where it originally came from, please add the recognition to this header.  Thank you, -Dominick
 * 
 * --CHANGELOG--
 * 6/9/2008 - Dominick O'Dierno odiernod@gmail.com
 *      Added the RealTimeItemProviders list
 * */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using DOMercury.Interfaces;

namespace DOMercury.Managers
{
    public static class PluginManager
    {
        private static List<IItemProvider> itemPlugins;
        private static List<IItemRealtimeProvider> itemRTPlugins;
        private static List<IActionProvider> actionPlugins;
        private static List<IParametersProvider> paramPlugins;
        private static List<ISubIndex> subIndexes;
        private static List<string> subindextypes;
        private static List<IDOMercuryUserInterfaceProvider> interfaces;
        public static void LoadPlugins()
        {
            itemPlugins = new List<IItemProvider>();
            itemRTPlugins = new List<IItemRealtimeProvider>();
            actionPlugins = new List<IActionProvider>();
            paramPlugins = new List<IParametersProvider>();
            subIndexes = new List<ISubIndex>();
            subindextypes = new List<string>();
            interfaces = new List<IDOMercuryUserInterfaceProvider>();
            string[] plugs;
            string[] intfcs;
            string path = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + "\\Plugins";
            string ipath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + "\\Interfaces";
            if (Directory.Exists(path))
            {
                plugs = Directory.GetFiles(path, "*.dll");
                List<Assembly> pl = new List<Assembly>();
                List<Type> at = new List<Type>();
                foreach (string p in plugs)
                {
                    //Load Plugin
                    pl.Add(Assembly.LoadFile(p));
                }

                foreach (Assembly ass in pl)
                {
                    try
                    {
                        at.AddRange(ass.GetTypes());
                    }
                    catch
                    {
                        System.Windows.Forms.MessageBox.Show("could not load plugins from assembly: " + ass.FullName);
                    }
                }
                //Grab ItemProviders
                List<Type> tl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(IItemProvider));
                });

                List<IItemProvider> temp;
                temp = tl.ConvertAll<IItemProvider>(delegate(Type t) { return Activator.CreateInstance(t) as IItemProvider; });
                foreach (IItemProvider p in temp)
                {
                    try
                    {
                        itemPlugins.Add(p);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with ItemProviderPlugin: " + p.Name + "\n" + ex.Message);
                    }
                }

                //Grab ItemRealTimeProviders
                List<Type> rtl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(IItemRealtimeProvider));
                });

                List<IItemRealtimeProvider> tempReal;
                tempReal = tl.ConvertAll<IItemRealtimeProvider>(delegate(Type t) { return Activator.CreateInstance(t) as IItemRealtimeProvider; });
                foreach (IItemRealtimeProvider p in tempReal)
                {
                    try
                    {
                        itemRTPlugins.Add(p);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with ItemRealtimeProviderPlugin: " + p.Name + "\n" + ex.Message);
                    }
                }

                //Grab ActionProviders
                List<Type> atl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(IActionProvider));
                });
                List<IActionProvider> temp2;
                temp2 = atl.ConvertAll<IActionProvider>(delegate(Type t) { return Activator.CreateInstance(t) as IActionProvider; });
                foreach (IActionProvider p in temp2)
                {
                    try
                    {
                        actionPlugins.Add(p);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with ActionProviderPlugin: " + p.Name + "\n" + ex.Message);
                    }
                }
                //Grab ParamProviders
                List<Type> ptl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(IParametersProvider));
                });
                List<IParametersProvider> temp3;
                temp3 = ptl.ConvertAll<IParametersProvider>(delegate(Type t) { return Activator.CreateInstance(t) as IParametersProvider; });
                foreach (IParametersProvider p in temp3)
                {
                    try
                    {
                        paramPlugins.Add(p);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with ParametersProviderPlugin: " + p.Name + "\n" + ex.Message);
                    }
                }
                //Grab sub indexes
                List<Type> stl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(ISubIndex));
                });
                List<ISubIndex> temp4;
                temp4 = stl.ConvertAll<ISubIndex>(delegate(Type t) { return Activator.CreateInstance(t) as ISubIndex; });
                foreach (ISubIndex p in temp4)
                {
                    try
                    {
                        subIndexes.Add(p);
                        subindextypes.Add(p.ParentItemType);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with subIndex: " + p.ParentItemType + "\n" + ex.Message);
                    }
                }

            }
            //Load Interfaces
            if (Directory.Exists(ipath))
            {
                intfcs = Directory.GetFiles(ipath, "*.dll");
                List<Assembly> pl = new List<Assembly>();
                List<Type> at = new List<Type>();
                foreach (string p in intfcs)
                {
                    //Load Plugin
                    pl.Add(Assembly.LoadFile(p));
                }

                foreach (Assembly ass in pl)
                {
                    try
                    {
                        at.AddRange(ass.GetTypes());
                    }
                    catch
                    {
                        System.Windows.Forms.MessageBox.Show("could not load plugins from assembly: " + ass.FullName);
                    }
                }
                List<IDOMercuryUserInterfaceProvider> itemp;
                //Grab ItemProviders
                List<Type> tl = at.FindAll(delegate(Type t)
                {
                    List<Type> interfaceTypes = new List<Type>(t.GetInterfaces());
                    object[] arr = t.GetCustomAttributes(typeof(DOMercuryPlugInAttribute), true);
                    return !(arr == null || arr.Length == 0) && interfaceTypes.Contains(typeof(IDOMercuryUserInterfaceProvider));
                });

                List<IItemProvider> temp;
                itemp = tl.ConvertAll<IDOMercuryUserInterfaceProvider>(delegate(Type t) { return Activator.CreateInstance(t) as IDOMercuryUserInterfaceProvider; });
                foreach (IDOMercuryUserInterfaceProvider p in itemp)
                {
                    try
                    {
                        interfaces.Add(p);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("Error with UserInterfaceProviderPlugin: " + p.Name + "\n" + ex.Message);
                    }
                }
            }
        }

        public static void UnloadPlugins()
        {
            itemPlugins.Clear();
            itemRTPlugins.Clear();
            actionPlugins.Clear();
            paramPlugins.Clear();
            subIndexes.Clear();
            subindextypes.Clear();
            interfaces.Clear();
            GC.Collect();
        }
        public static List<IItemProvider> ItemProviders
        {
            get
            {
                return itemPlugins;
            }
        }

        public static List<IItemRealtimeProvider> RealTimeItemProviders
        {
            get
            {
                return itemRTPlugins;
            }
        }

        public static List<IActionProvider> ActionProviders
        {
            get
            {
                return actionPlugins;
            }
        }

        public static List<IParametersProvider> ParamProviders
        {
            get
            {
                return paramPlugins;
            }
        }

        public static List<ISubIndex> SubIndexes
        {
            get
            {
                return subIndexes;
            }
        }

        public static List<string> SubIndexTypes
        {
            get
            {
                return subindextypes;
            }
        }

        public static bool HasSubIndex(string type)
        {
            return subindextypes.Contains(type);
        }

        public static List<IDOMercuryUserInterfaceProvider> UserInterfaces
        {
            get
            {
                return interfaces;
            }
        }

    }


}
